<template>
	<div class="hello"></div>
</template>

<script>
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
// import { TransformControls } from 'three/examples/jsm/controls/TransformControls.js';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';

let renderer,
	camera,
	scene,
	objects = [],
	isRotate = true;

import { GUI } from 'dat.gui';
const gui = new GUI();
export default {
	name: 'HelloWorld',
	props: {
		msg: String
	},
	created() {
		this.main();
		this.setScene();
		this.setCamera();
		this.setLight();
		this.setObjts();
		this.renderThree();
		this.orthers();
		// 3d物体点击事件
		window.addEventListener('click', event => {
			event.preventDefault();
			const vector = new THREE.Vector3(); //三维坐标对象
			vector.set((event.clientX / window.innerWidth) * 2 - 1, -(event.clientY / window.innerHeight) * 2 + 1, 0.5);
			vector.unproject(camera);
			const raycaster = new THREE.Raycaster(camera.position, vector.sub(camera.position).normalize());
			const intersects = raycaster.intersectObjects(scene.children, true);
			// console.log(intersects);
			if (intersects.length > 0) {
				// const selected = intersects[0]; //取第一个物体
				// console.log(selected);
				// console.log('x坐标:' + selected.point.x);
				// console.log('y坐标:' + selected.point.y);
				// console.log('z坐标:' + selected.point.z);
				for (let item of intersects) {
					if (item.object.type == 'Mesh' && item.object.name == 'floor') {
						item.object.material.color.set(0xfff000);
						return;
					} else if (item.object.type == 'Mesh') {
						return;
					}
				}
			}
		});
	},
	methods: {
		main() {
			renderer = new THREE.WebGLRenderer();
			renderer.setSize(window.innerWidth, window.innerHeight);
			// add the output of the render function to the HTML
			document.body.appendChild(renderer.domElement);
		},
		setScene() {
			scene = new THREE.Scene();
			// scene.background = new THREE.Color("#eee");

			/**
			 * dat
			 */
			let guiControls = {
				rx: 0,
				ry: 1.6,
				rz: 0
			};
			scene.rotation.y = guiControls.ry;

			const folder = gui.addFolder('场景ratition设置');
			folder
				.add(guiControls, 'rx', -10, 10, 0.1)
				.name('场景rotation_x:')
				.onChange(e => {
					scene.rotation.x = e;
				});
			folder
				.add(guiControls, 'ry', -10, 10, 0.1)
				.name('场景rotation_y:')
				.onChange(e => {
					scene.rotation.y = e;
				});
			folder
				.add(guiControls, 'rz', -10, 10, 0.1)
				.name('场景rotation_z:')
				.onChange(e => {
					scene.rotation.z = e;
				});
		},
		setCamera() {
			/**
			 * dat
			 */
			let guiControls = {
				near: 0.01,
				far: 1000,
				fov: 75,
				ax: 0,
				ay: 16,
				az: 0
			};

			camera = new THREE.PerspectiveCamera(guiControls.fov, window.innerWidth / window.innerHeight, guiControls.near, guiControls.far);
			camera.position.set(0, 39, 29);
			camera.lookAt(guiControls.ax, guiControls.ay, guiControls.az);

			console.log(camera.up);

			// const cameraHelper = new THREE.CameraHelper(camera);
			// cameraHelper.visible = true;
			// scene.add(cameraHelper);

			const folder = gui.addFolder('相机设置');
			folder
				.add(guiControls, 'near', 0.1, 1000, 0.1)
				.name('相机near:')
				.onChange(e => {
					camera.near = e;
					camera.updateProjectionMatrix();
					console.log(camera.updateProjectionMatrix);
				});
			folder
				.add(guiControls, 'far', 1, 10000, 10)
				.name('相机far:')
				.onChange(e => {
					camera.far = e;
					camera.updateProjectionMatrix();
				});
			folder
				.add(guiControls, 'fov', 50, 150, 1)
				.name('相机fov:')
				.onChange(e => {
					camera.fov = e;
					camera.updateProjectionMatrix();
				});
			folder
				.add(guiControls, 'ax', -50, 50, 0.1)
				.name('相机lookAt _x:')
				.onChange(e => {
					camera.lookAt(e, guiControls.ay, guiControls.az);
				});
			folder
				.add(guiControls, 'ay', -50, 50, 0.1)
				.name('相机lookAt _y:')
				.onChange(e => {
					camera.lookAt(guiControls.ax, e, guiControls.az);
				});
			folder
				.add(guiControls, 'az', -50, 50, 0.1)
				.name('相机lookAt _z:')
				.onChange(e => {
					camera.lookAt(guiControls.ax, guiControls.ay, e);
				});
		},
		setLight() {
			{
				/**
				 * dat
				 */
				let guiControls = {
					lx: 1,
					ly: 38,
					lz: -6,
					lcolor: '#fff',
					intensity: 0.78,
					lj: -5
				};

				const light = new THREE.PointLight(guiControls.lcolor, guiControls.intensity);
				light.position.set(guiControls.lx, guiControls.ly, guiControls.lz);
				scene.add(light);

				const helper = new THREE.PointLightHelper(light);
				scene.add(helper);

				const folder = gui.addFolder('灯光设置');
				folder
					.add(guiControls, 'lx', -40, 40, 1)
					.name('灯光x:')
					.onChange(e => {
						light.position.set(e, guiControls.ly, guiControls.lz);
					});
				folder
					.add(guiControls, 'ly', -40, 40, 1)
					.name('灯光y:')
					.onChange(e => {
						light.position.set(guiControls.lx, e, guiControls.lz);
					});
				folder
					.add(guiControls, 'lz', -40, 40, 1)
					.name('灯光z:')
					.onChange(e => {
						light.position.set(guiControls.lx, guiControls.ly, e);
					});
				folder
					.addColor(guiControls, 'lcolor')
					.name('灯光颜色:')
					.onChange(e => {
						light.color = new THREE.Color(e);
					});
				folder.add(light, 'intensity', 0, 2, 0.01);
			}
		},
		async setObjts() {
			// 创建几何体
			const homeObj = new THREE.Object3D();
			homeObj.name = 'homeObj';
			homeObj.position.set(0, 0, 0);
			scene.add(homeObj);
			objects.push(homeObj);

			const loader = new THREE.TextureLoader();

			/**
			 *  objName  : string
			 * fatherObj: THREE.Object3D
			 * position :array   [x,y,z]
			 * size  :array   [z,y,z] 大小
			 * texture: 纹理地址
			 */
			function genderWall(objName, fatherObj, position = [0, 0, 0], size, color, texture) {
				// 创建几何体
				const obj = new THREE.Object3D();
				obj.name = objName;
				obj.position.set(...position);
				fatherObj.add(obj);
				objects.push(obj);

				if (size) {
					// 有大小则说明是cube
					const geometry = new THREE.BoxGeometry(...size);
					const material = new THREE.MeshPhongMaterial({
						color: color ? color : null,
						map: texture ? loader.load(texture) : null
					});
					const cube = new THREE.Mesh(geometry, material);
					cube.name = objName;
					obj.add(cube);
				}
				return obj;
			}
			// 房屋
			const houseObj = genderWall('house', homeObj);
			// 地板

			const floorObj = genderWall('floor', houseObj, [0, 0, 0], [32, 0.2, 32], false, '/static/texture/white_marble_tiles_3_diffuse.png');
			// 墙面
			// 位置通过计算
			genderWall('wall1', houseObj, [0, 16, -16], [32, 32, 0.2], 0xffffff);
			genderWall('wall2', houseObj, [0, 16, 16], [32, 32, 0.2], 0xffffff);
			genderWall('wall3', houseObj, [16, 16, 0], [0.2, 32, 32], 0xffffff);
			// genderWall('wall3', houseObj, [-16, 16, 0], [0.2, 32, 32], 0xffffff);

			// 台座
			const pedestalObj = new THREE.Object3D();
			pedestalObj.name = 'pedesta';
			pedestalObj.position.set(0, 0.4, 0);
			homeObj.add(pedestalObj);
			objects.push(pedestalObj);
			const geometry = new THREE.ConeGeometry(6, 9, 20);
			const material = new THREE.MeshPhongMaterial({
				// color:0xff0000,
				map: loader.load('/static/texture/glass_texture.jpg')
			});
			const cube = new THREE.Mesh(geometry, material);
			cube.rotation.x = 3.15;
			pedestalObj.add(cube);

			const carObj = genderWall('car', pedestalObj, [0, 6.7, 0]);
			const gltf = await this.loadFile('/static/3d/car/tesla_model_p100d/scene.gltf');
			gltf.scene.scale.set(3, 3, 3);

			// const gltf = await this.loadFile(
			//   "/static/3d/level_02_-_vr_platform_game_on_sketchfab/scene.gltf"
			// );
			/**
			 * 显示不出来是因为大小原因
			 */
			// gltf.scene.scale.set(0.003766, 0.003766, 0.003766);
			carObj.add(gltf.scene);
			// figureObj.position.set(0, 0, 10);
			// figureObj.scale.set(0.01, 0.01, 0.01);
			this.setTextrue();
			/**
			 * dat
			 */
			// let guiControls = {
			//   scale: 0.1,
			// };
			// const folder = gui.addFolder("模型设置");
			// folder
			//   .add(guiControls, "scale", 0.00001, 0.01, 0.000001)
			//   .name("模型缩放:")
			//   .onChange((e) => {
			//     gltf.scene.scale.set(e, e, e);

			//     // figureObj.scale.set(e, e, e);
			//   });

			// const axesHelper = new THREE.AxesHelper(2);
			// figureObj.add(axesHelper);

			// genderWall("wall4", houseObj, [-4, 4, 0], [0.2, 8, 8], 0xffffff);

			// Turns both axes and grid visible on/off
			// GUI requires a property that returns a bool
			// to decide to make a checkbox so we make a setter
			// can getter for `visible` which we can tell GUI
			// to look at.
			class AxisGridHelper {
				constructor(node, units = 10) {
					const axes = new THREE.AxesHelper();
					axes.material.depthTest = false;
					axes.renderOrder = 2; // after the grid
					node.add(axes);

					const grid = new THREE.GridHelper(units, units);
					grid.material.depthTest = false;
					grid.renderOrder = 1;
					node.add(grid);

					this.grid = grid;
					this.axes = axes;
					this.visible = false;
				}
				get visible() {
					return this._visible;
				}
				set visible(v) {
					this._visible = v;
					this.grid.visible = v;
					this.axes.visible = v;
				}
			}

			function makeAxisGrid(node, label, units) {
				const helper = new AxisGridHelper(node, units);
				gui.add(helper, 'visible').name(label);
			}

			makeAxisGrid(homeObj, 'homeObj', 26);
			makeAxisGrid(houseObj, 'houseObj');
			makeAxisGrid(floorObj, 'floorObj');

			/**
			 * dat
			 */
			let guiControls = {
				px: 0,
				py: 0,
				pz: 0,
				rx: 0,
				ry: 0,
				rz: 0
			};

			const folder = gui.addFolder('墙面设置');
			folder
				.add(guiControls, 'px', -5, 5, 0.1)
				.name('x:')
				.onChange(e => {
					floorObj.position.set(e, guiControls.py, guiControls.pz);
				});
			folder
				.add(guiControls, 'py', -5, 5, 0.1)
				.name('y:')
				.onChange(e => {
					floorObj.position.set(guiControls.px, e, guiControls.pz);
				});
			folder
				.add(guiControls, 'pz', -5, 5, 0.1)
				.name('z:')
				.onChange(e => {
					floorObj.position.set(guiControls.px, guiControls.py, e);
				});
			folder
				.add(guiControls, 'rx', -5, 5, 0.1)
				.name('ritationx_x:')
				.onChange(e => {
					floorObj.rotation.x = e;
				});
			folder
				.add(guiControls, 'ry', -5, 5, 0.1)
				.name('ritationx_y:')
				.onChange(e => {
					floorObj.rotation.y = e;
				});
			folder
				.add(guiControls, 'rz', -5, 5, 0.1)
				.name('ritationx_z:')
				.onChange(e => {
					floorObj.rotation.z = e;
				});
		},
		renderThree() {
			function resizeRendererToDisplaySize(renderer) {
				const canvas = renderer.domElement;
				const pixelRatio = window.devicePixelRatio;
				const width = (canvas.clientWidth * pixelRatio) | 0;
				const height = (canvas.clientHeight * pixelRatio) | 0;
				const needResize = canvas.width !== width || canvas.height !== height;
				if (needResize) {
					renderer.setSize(width, height, false);
				}
				return needResize;
			}
			function render(time) {
				time *= 0.001;
				if (resizeRendererToDisplaySize(renderer)) {
					const canvas = renderer.domElement;
					camera.aspect = canvas.clientWidth / canvas.clientHeight;
					camera.updateProjectionMatrix();
				}
				objects.forEach(item => {
					// console.log(item);
					if (isRotate && item.name == 'pedesta1') {
						item.rotation.y = time;
					}
				});
				renderer.render(scene, camera);
				requestAnimationFrame(render);
			}
			requestAnimationFrame(render);
		},
		orthers() {
			// 轨道控制器
			const controls = new OrbitControls(camera, renderer.domElement);
			// controls.minPolarAngle = 0.5 * Math.PI;
			controls.maxPolarAngle = (0.9 * Math.PI) / 2;
			controls.enableZoom = true;
			// 获取改变后的相机位置
			let timer;
			controls.addEventListener('end', () => {
				clearTimeout(timer);
				timer = setTimeout(() => {
					console.log(camera.position);
				}, 3000);
			});

			// // // 这里我们使用变换控制器 用来改变车辆的方向
			// const transformControls = new TransformControls(camera, renderer.domElement);
			// // 添加到场景中
			// scene.add(transformControls);
			// // 查找车辆obj
			// const index = objects.findIndex(item => {
			// 	return item.name == 'car';
			// });
			// transformControls.object = objects[index];
			// transformControls.mode = 'rotate';
			// transformControls.showX = false;
			// transformControls.showZ = false;
			// transformControls.setRotationSnap(0.01);
			// // 旋转操作判断
			// let timer;
			// transformControls.addEventListener('dragging-changed', e => {
			// 	if (e.value) {
			// 		// 人为操作时取消自动旋转
			// 		isRotate = false;
			// 		console.log('timer:', timer);
			// 		clearTimeout(timer);
			// 		return;
			// 	}
			// 	// 无操作时开启旋转
			// 	timer = setTimeout(() => {
			// 		isRotate = true;
			// 	}, 5000);
			// });
		},
		//加载模型
		loadFile(url) {
			const loader = new GLTFLoader(); //引入模型的loader实例
			return new Promise((resolve, reject) => {
				loader.load(
					url,
					gltf => {
						console.log('模型', gltf);
						resolve(gltf);
					},
					({ loaded, total }) => {
						// let load = Math.abs((loaded / total) * 100);
						// this.loadingWidth.value = load;
						// if (load >= 100) {
						//   setTimeout(() => {
						//     this.isLoading.value = false;
						//   }, 1000);
						// }
						console.log((loaded / total) * 100 + '% loaded');
					},
					err => {
						reject(err);
					}
				);
			});
		},
		/**
		 * 设置贴图、颜色
		 */
		setTextrue() {
			const textrueGender = url => {
				return new THREE.TextureLoader().load(
					// 由于当前使用的都是本地的贴图所以我们设置成本地的路径
					'/static/3d/blender_collab_15.0_final_scene/textures/' + url
				);
			};
			let texture = {
				Plane_6: {
					zurl: 'chelun.jpg'
				},
				// 车身颜色
				door_dside_r_primary_0: {
					zcolor: 'yellow'
				},
				// 玻璃颜色
				glass_rr001_glass_0: {
					zcolor: '#272727'
				},
				// 玻璃颜色
				boot_bodyshell7_0: {
					zcolor: 'red'
				}
			};

			scene.traverse(child => {
				if (child.isMesh) {
					console.log(child.name);
					for (const key in texture) {
						const itemInfo = texture[key];
						if (key == child.name && itemInfo.zurl) {
							// 设置贴图
							child.material.map = textrueGender(itemInfo.zurl);
						}
						if (key == child.name && itemInfo.zcolor) {
							// 设置颜色
							child.material.color.set(itemInfo.zcolor);
						}
					}
				}
			});
		}
	}
};
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped></style>
